#!/usr/bin/env python
# -*- coding: UTF-8 -*-

try:
	import pdb
	import sys
	import pygame
	import pygame.font
	import lib.utils
	from lib.animateable import *
	from lib.command import Command
	from pygame.font import *
	from pygame.locals import *
except ImportError, err:
	print "Could not load %s module." % (err)
	sys.exit(2)

'''
Menu

The menu window is composed of two separate sprites: one semi-
transparent coloured background; and a sprite with a fully transparent
colorkey, where the window borders, menu options, and menu cursor are
blitted into.

In contrast with Battlefield, Creature, and Cursor, Menu doesn't use
(x, y) as its top left corner; it uses "top" and "left" because "y" is
used to "animate" the opening and closing of windows ("x" is unused).
'''

class Menu(pygame.sprite.DirtySprite, Animateable):
	def __init__(self):
		# only stuff that is not content-dependent gets initialized here
		pygame.sprite.DirtySprite.__init__(self)
		Animateable.__init__(self)

		self.parent_window = None

		# load tiles
		source = lib.utils.get_window_surface()
		self.corner_tile = source.subsurface(((16 * 2, 0), (16, 16)))
		self.side_tile = source.subsurface(((16 * 3, 0), (16, 16)))
		self.cursor = source.subsurface(((0, 16 * 8), (16, 16)))
		self.blank_tile = source.subsurface(((16, 16 * 4), (16, 16)))

		# save tile size (it gets used lots)
		self.tile_x = self.corner_tile.get_width()
		self.tile_y = self.corner_tile.get_height()

		self.font = lib.utils.get_window_font()
		self.colorkey = self.corner_tile.get_at((15, 15))
		self.top = self.left = 72
		self.title = ''
		self.options = {}


	def prerender(self, layers):
		self.layers = layers
		self.create_cursor_positions()

		# preset menu window dimensions to longest menu option
		self.width, self.height = self.get_content_size()
		# add room for arrow cursor and menu frame
		self.width += self.tile_x * 3
		# height is that of a single option at this point
		# get full menu height and add room for menu frame
		self.height = (self.height * len(self.options)) + (self.tile_y * 2)
		if len(self.title):
			self.height += self.tile_y + self.r_title.get_height()

		self.rect = pygame.rect.Rect((self.left, self.top, self.width, self.height))

		self.image = pygame.Surface((self.width, self.height)).convert()
		self.image.fill(self.colorkey)
		self.image.set_colorkey(self.colorkey, RLEACCEL)

		self.blit_border()
		self.blit_contents()
		self.stored_image = self.image.copy()
		self.create_background()

		self.show()


	def create_cursor_positions(self):
		'''
		The use of tile_x and tile_y in this function assumes that
		corner_tile and cursor_tile have the same dimensions.

		It is also assumed that the rendered text surface height is
		at least as large as the cursor arrow (tile_y or 16px).
		'''
		self.cursor_positions = []
		font_height = self.font.get_height()
		cursor_top = self.tile_y
		if len(self.title):
			cursor_top += font_height + self.tile_y
		# if font height is different from tile_y, center the tile
		cursor_top += (font_height - self.tile_y) // 2
		for i in range(len(self.options)):
			self.cursor_positions.append([self.tile_x, cursor_top])
			cursor_top += font_height
		self.cursor_draw = 0
		self.cursor_erase = 0

	def get_content_size(self):
		# actually prerenders the options
		self.r_options = []
		temp_size = (0, 0)
		for element in self.options:
			# element is a string
			text = self.font.render(element.name, True, WHITE, self.colorkey)
			current_size = text.get_size()
			if temp_size[0] < current_size[0]:
				temp_size = current_size
			self.r_options.append(text)
		if len(self.title):
			self.r_title = self.font.render(self.title, True, WHITE, self.colorkey)
			if temp_size[0] < self.r_title.get_size()[0]:
				temp_size = self.r_title.get_size()
		return temp_size

	def create_background(self):
		self.background = pygame.sprite.DirtySprite()
		self.background.image = pygame.Surface((self.width, self.height)).convert()
		self.background.rect = self.rect
		self.background.image.fill(MenuBackgroundColor)
		self.background.image.set_alpha(192, RLEACCEL)
		self.background.stored_image = self.background.image.copy()

	def blit_border(self):
		width_sans_tile = self.width - self.tile_x
		height_sans_tile = self.height - self.tile_y

		# blit frame edges - top, right, bottom, left
		for i in range(self.tile_x, width_sans_tile, self.tile_x):
			self.image.blit(self.side_tile, ((i, 0)))
		self.side_tile = pygame.transform.rotate(self.side_tile, -90)
		for i in range(self.tile_y, height_sans_tile, self.tile_y):
			self.image.blit(self.side_tile, ((width_sans_tile, i)))
		self.side_tile = pygame.transform.rotate(self.side_tile, -90)
		for i in range(self.tile_x, width_sans_tile, self.tile_x):
			self.image.blit(self.side_tile, ((i, height_sans_tile)))
		self.side_tile = pygame.transform.rotate(self.side_tile, -90)
		for i in range(self.tile_y, height_sans_tile, self.tile_y):
			self.image.blit(self.side_tile, ((0, i)))
		#self.side_tile = pygame.transform.rotate(self.side_tile, -90)

		# blit corners - from top left clockwise
		self.image.blit(self.corner_tile, ((0, 0)))
		self.corner_tile = pygame.transform.flip(self.corner_tile, 1, 0)
		self.image.blit(self.corner_tile, ((width_sans_tile, 0)))
		self.corner_tile = pygame.transform.flip(self.corner_tile, 0, 1)
		self.image.blit(self.corner_tile, ((width_sans_tile, height_sans_tile)))
		self.corner_tile = pygame.transform.flip(self.corner_tile, 1, 0)
		self.image.blit(self.corner_tile, ((0, height_sans_tile)))
		#self.corner_tile = pygame.transform.flip(self.corner_tile, 0, 1)

	def blit_contents(self):
		content_top = self.tile_y
		if len(self.title):
			title_left = (self.width - self.r_title.get_width()) // 2
			self.image.blit(self.r_title, ((title_left, content_top)))
			content_top += self.r_title.get_height() + self.tile_y
		for element in self.r_options:
			# element is a surface
			self.image.blit(element, ((2 * self.tile_x, content_top)))
			content_top += self.font.get_height()

	def update(self):
		if self.animating != []:
			self.slide()
			self.background.image = self.background.stored_image.subsurface((0, 0, self.width, self.y))
			self.image = self.stored_image.subsurface(0, 0, self.width, self.y)	
			self.dirty = 1

		self.image.blit(self.blank_tile, (self.cursor_positions[self.cursor_erase]))
		self.image.blit(self.cursor, (self.cursor_positions[self.cursor_draw]))

	def move(self, key, mod):
		return self.move_cursor(key)

	def move_cursor(self, key):

		if key == K_UP:
			self.cursor_erase = self.cursor_draw
			self.cursor_draw = (self.cursor_draw - 1) % len(self.options)
			self.dirty = 1
		elif key == K_DOWN:
			self.cursor_erase = self.cursor_draw
			self.cursor_draw = (self.cursor_draw + 1) % len(self.options)
			self.dirty = 1
		return True

	def do_action(self, engine):
		inputhandler = self.options[self.cursor_draw].func()
		if inputhandler != None:
			inputhandler.open()
			#~ pdb.set_trace()
			engine.inputstack.append(inputhandler)

	def open(self):
		self.x = self.y = 0
		self.background.image = self.background.stored_image.subsurface((0, 0, self.width, 0))
		self.image = self.stored_image.subsurface((0, 0, self.width, 0))
		self.set_anim_params(self.height, 12)
		self.animating.append(K_DOWN)

	def close(self):
		self.animating.append(K_UP)
		self.set_end_event_name('WINDOW_CLOSED')

	def kill(self):
		'''	Remove the sprites from all groups '''
		pygame.sprite.DirtySprite.kill(self)
		self.background.kill()

	def hide(self):
		self.bg.remove(self.background)
		self.fg.remove(self)
		self.x = self.y = 0

	def show(self):
		"""
		Shows the Panel in layers 7 and 8
		"""
		self.layers.add(self.background, layer = 7)
		self.layers.add(self, layer = 8)


'''
Subclasses of Menu
'''

class SaveWindow(Menu):
	def __init__(self, parent):
		Menu.__init__(self)
		self.title = 'Save Where?'
		self.options = (
			Option('1',	''),
			Option('2',	''),
			Option('3',	''),
			Option('4',	''),
			Option('5',	''),
			Option('6',	''),
			Option('7',	''),
			Option('8',	''),
			Option('9',	''),
			Option('10',''),
		)
		self.left += parent.width
		self.parent_window = parent
		self.prerender(parent.layers)

class SystemMenu(Menu):
	def __init__(self, layers):
		Menu.__init__(self)
		self.options = (
			Option('Save Game',	(lambda: SaveWindow(parent = self))),
			Option('Load Game',	'LoadWindow'),
			Option('Objectives', '(lambda : CenteredMessageWindow(scenario.objectives))'),
			Option('Options',	'OptionsWindow'),
			Option('End Phase',	'scenario.end_phase')
		)
		self.prerender(layers)

class CreatureMenu(Menu):
	def __init__(self, layers, creature):
		Menu.__init__(self)
		#self.options = creature.action_menu_options
		self.options = (
			Option('Move',	(lambda: self.command("Move", creature))),
			Option('Attack', (lambda: self.command("Attack", creature))),
			Option('Magic',	'(lambda : Window(creature.magic))'),
			Option('Summon',	'(lambda : Window(creature.summon))'),
			Option('Rally',	'(lambda : do_rally(creature))'),
			Option('Tactics',	'(lambda : Window(creature.tactics))'),
		)
		self.prerender(layers)
		self.creature = creature

	def command(self, type, creature):
		"""
		Generic command call from the menu - closes itself and calls creature
		command
		"""
		self.close()
		if type == "Attack":
			creature.command("Attack")
		elif type == "Move":
			creature.command("Move")

			
'''
Option Class

The contents of Menu.options need to be in order, and each option needs
at least two members: a name, and a function to call. Thus, a simple
dictionary of name:func pairs results insufficient, and a list of
Option objects is used.
'''
class Option(object):
	def __init__(self, name, func):
		self.name = name
		self.func = func
